/**
 * is用于判断类型是否满足需求
 * @param {any} value 需要校验的值
 * @param {string} type 校验的类型
 * */
export const is = function(value: any, type: string): boolean
{
    // return toString.call(val) === `[object ${type}]`;
    return Object.prototype.toString.call(value) === `[object ${type}]`;
};

/**
 * 判断是否为数字类型
 * @param {any} value 传递需要检验的值
 * */
export const isNumber = function(value: any): value is number
{
    // return value.constructor === Number;
    // return Object.prototype.toString.call(value) === "[object Number]";
    return is(value, "Number");
};

/**
 * 判断是否为对象类型
 * @param {any} value 传递需要检验的值
 * */
export const isObject = function(value: any): value is Record<string, any>
{
    // return value.constructor === Object;
    // return Object.prototype.toString.call(value) === "[object Object]";
    return value !== null && is(value, "Object");
};

/**
 * 判断是否为数组类型
 * @param {any} value 传递需要检验的值
 * */
export const isArray = function(value: any): value is Array<any>
{
    // return value.constructor === Array;
    // return Object.prototype.toString.call(value) === "[object Array]";
    return value !== null && is(value, "Array");
};

/**
 * 判断是否为字符串
 * @param {any} value 传递需要检验的值
 * */
export const isString = function(value: any): value is string
{
    // return value.constructor === String;
    // return Object.prototype.toString.call(value) === "[object String]";
    return is(value, "String");
};

/**
 * 判断是否为函数
 * @param {any} value 传递需要检验的值
 * */
export const isFunction = function(value: any): value is Function
{
    // return value.constructor === Function;
    // return Object.prototype.toString.call(value) === "[object Function]";
    return is(value, "Function");
};

/**
 * 判断是否为布尔
 * @param {any} value 传递需要检验的值
 * */
export const isBoolean = function(value: any): value is boolean
{
    // return value.constructor === Boolean;
    // return Object.prototype.toString.call(value) === "[object Boolean]";
    return is(value, "Boolean");
};

/**
 * 判断是否为Promise
 * @param {any} value 传递需要检验的值
 * */
export const isPromise = function(value: any): value is Promise<any>
{
    // return value.constructor === Promise;
    // return Object.prototype.toString.call(value) === "[object Promise]";
    return is(value, "Promise");
};

/**
 * 判断是否为空对象
 * @param {any} value 传递需要检验的值
 * */
export const isEmpty = function <T = unknown>(value: T): boolean
{
    // return JSON.stringify(value) === "{}";

    if (isArray(value))
    {
        return value.length === 0;
    }
    else if (isObject(value))
    {
        return Object.keys(value).length === 0;
    }
    else if (value instanceof Map || value instanceof Set)
    {
        return value.size === 0;
    }
    else
    {
        return false;
    }
};

/**
 * 判断两个对象是否相等
 * @param {object | array | string | number} first 第一个参数对象
 * @param {object | array | string | number} second 第二个参数对象
 * */
export const isEqual = function(first?: Record<string, any> | Array<any> | string | number, second?: Record<string, any> | Array<any> | string | number): boolean
{
    // 首先判断两个都是一样的对象
    if (isObject(first) && isObject(second))
    {
        const firstData = first as Record<string, any>;

        const secondData = second as Record<string, any>;

        const keys1 = Object.keys(firstData);

        const keys2 = Object.keys(secondData);

        // 比较key的长度
        if (keys1.length !== keys2.length)
        {
            return false;
        }

        // 遍历对象,看对象的值是否相等
        for (const k in firstData)
        {
            if (isObject(firstData[k]) && isObject(secondData[k]) || isArray(firstData[k]) && isArray(secondData[k]))
            {
                if (!isEqual(firstData[k], secondData[k]))
                {
                    return false;
                }
            }
            else if (firstData[k] !== secondData[k])
            {
                return false;
            }
        }

        return true;
    }
    else if (isArray(first) && isArray(second))
    {
        const firstData = first as any[];

        const secondData = second as any[];

        if (firstData.length !== secondData.length)
        {
            return false;
        }

        const length = firstData.length;

        for (let i = 0; i < length; i++)
        {
            const firstValue = firstData[i];

            if (isObject(firstData[i]) && isObject(secondData[i]) || isArray(firstData[i]) && isArray(secondData[i]))
            {
                if (!isEqual(firstData[i], secondData[i]))
                {
                    return false;
                }
            }
            // 当前值不出现在另一个数组内,则为假
            else if (!secondData.includes(firstValue))
            {
                return false;
            }
        }

        return true;
    }
    else if (isString(first) && isString(second) || isNumber(first) && isNumber(second))
    {
        return first === second;
    }
    else
    {
        return typeof first === typeof second;
    }
};

/**
 * 日志输出
 * @param {array} message 警告内容
 * */
export const log = function(...message: any[]): void
{
    // eslint-disable-next-line no-console
    console.log(...message);
};

/**
 * 警告输出
 * @param {array} message 警告内容
 * */
export const warn = function(...message: any[]): void
{
    // eslint-disable-next-line no-console
    console.warn(...message);
};

/**
 * 错误输出
 * @param {array} message 错误内容
 * */
export const error = function(...message: any[]): void
{
    // eslint-disable-next-line no-console
    console.error(...message);
};

/**
 * 正则
 * */
export const regular = {
    special: "[`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？]", // 特殊字符
    simpleSpecial: "[~!@#$^&*()=|{}':;',\\[\\]<>/?]", // 简单(常用)的特殊字符
    alphabet: /^[\u4E00-\u9FA5a-zA-Z]*$/, // 只允许输入中文和字母
    phone: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, // 手机号码
    email: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, // 电子邮箱
    letter: /[a-zA-Z]/, // 只允许英文字母
    letterNumber: /^[A-Za-z0-9]+$/, // 只允许字母和数字
    number: /^[+-]?(0|([1-9]\d*))(\.\d+)?$/, // 数字(正数、负数，小数)
    unNegativeNumber: /^[0-9]+([.]{0,1}[0-9]+){0,1}$/, // 非负数字(0, 整数, 小数)
    positiveInteger: /^[1-9]\d*$/, // 正整数
    negativeInteger: /^-[1-9]\d*$/, // 负整数
    nonzeroInteger: /^-?[1-9]\d*$/, // 非零整数
    nonnegativeInteger: /^[0-9]\d*$/, // 非负整数(含0)
    float: /^(0|[+-]?((0|([1-9]\d*))\.\d+)?)$/, // 浮点数
    nonzeroFloat: /^[+-]?((0|([1-9]\d*))\.\d+)?$/, // 非零浮点数
    positiveFloat: /^(?:[1-9][0-9]*\.[0-9]+|0\.(?!0+$)[0-9]+|0)$/, // 正浮点数
    nonzeroPositiveFloat: /^(?:[1-9][0-9]*\.[0-9]+|0\.(?!0+$)[0-9]+)$/, // 非零正浮点数
    negativeFloat: /^(0|-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))$/, // 负浮点数
    nonzeroNegativeFloat: /^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/, // 非零负浮点数
    date: /^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))$/, // 日期校验
    time: /([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/, // 时间校验
    dateTime: /^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/, // 日期时间校验
    url: /(http|https):\/\/\S*/, // 校验url地址
    identityCard: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, // 校验身份证
    integerDecimalNumber: /^(([1-9]\d*)(\.\d+)?)$|^0\.\d*[1-9]$/, // 整数、小数，但是不能为0\0.0
    passport: /^[A-Z0-9]{5,15}$/, // 护照
    chinese: /^[\u4e00-\u9fa5]+$/, // 中文
    chineseNumber: /^[\u4e00-\u9fa5\d]+$/, // 中文和数字
    chineseNumberSpecial: /^[\u4e00-\u9fa5\d\s\S]+$/ // 中文、数字、空格、特殊字符
};